/*
    Copyright (C) <2010>  <Markus Scharnowski markus.scharnowski@gmail.com>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <QFileDialog>
#include <QMessageBox>
#include <QDataStream>
#include <QApplication>
#include <QLayout>
#include <QInputDialog>
#include <QTextCodec>
#include <QDir>

#include <assert.h>
#include <sstream>
#include <iomanip>
#include <iostream>
#include <fstream>

#include "mainwindow.h"
#include "aboutdialog.hpp"
#include "showfulllistdialog.hpp"

//#define MCE_SCREENSAVER_HANDLING
#define QT_SCREENSAVER_HANDLING
#ifdef MCE_SCREENSAVER_HANDLING
#ifdef Q_WS_MAEMO_5
#include <QtDBus/QtDBus>
#include <mce/mode-names.h>
#include <mce/dbus-names.h>
#endif
#endif
#ifdef QT_SCREENSAVER_HANDLING
#ifdef Q_WS_MAEMO_5
#include <QtMaemo5/QtMaemo5>
#include <QSystemScreenSaver>
#endif
#endif

#define DEBUG_OUTPUT
#undef DEBUG_OUTPUT
#define DEBUG_EVENT_OUTPUT
#undef DEBUG_EVENT_OUTPUT

/**
Globals
*/

/**
Implementation
*/

/**
  Constructor
*/
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
  snprintf(mainButtonStartText,BUFSIZ-1,
           "&Start"
           );
  setupUi();
  fsExitButton = new FullScreenExitButton(this);
  fsExitButton->hide();

  timer = new QTimer(this);
  connect(timer, SIGNAL(timeout()), this, SLOT(mainButtonTimeoutUpdate()));
  timerRefreshTimeMs = 100;

  /**
    Signal connections
  */
  connect(actionReset, SIGNAL(triggered()), this , SLOT(resetProgram()));
  connect(actionPause, SIGNAL(triggered()), this , SLOT(pauseCounting()));
  connect(actionStartStopMode, SIGNAL(triggered()), this, SLOT(toggleStartStopMode()));

  connect(actionEnable_full_date, SIGNAL(triggered()), this , SLOT(toggleFullDate()));
  connect(actionEnable_time_and_date, SIGNAL(triggered()), this , SLOT(toggleTimeDate()));
  connect(actionShow_full_list, SIGNAL(triggered()), this , SLOT(showFullList()));

  connect(action_Fullscreen, SIGNAL(triggered()), this, SLOT(showFullScreenHandler()));
  connect(actionResetFs, SIGNAL(triggered()), this , SLOT(resetProgramAndFullscreen()));
  connect(actionChangeNumberOfLines, SIGNAL(triggered()), this, SLOT(changeNumberOfLines()));
  connect(actionChangeFontSize, SIGNAL(triggered()), this, SLOT(changeFontSize()));
  connect(actionUseDeltaTime, SIGNAL(triggered()), this, SLOT(toggleUseDeltaTime()));
#ifdef Q_WS_MAEMO_5
  connect(actionDisableScreensaver, SIGNAL(triggered()), this, SLOT(toggleDisableScreensaver()));
#endif

  connect(actionAbout, SIGNAL(triggered()), this , SLOT(about()));

  connect(this->mainButton, SIGNAL(clicked()), this, SLOT(mainButtonHandler()));

#ifdef DO_SCREEN_HANDLING
  dBusInterface = new QDBusInterface(MCE_SERVICE, MCE_REQUEST_PATH,
                                     MCE_REQUEST_IF, dBusConnection, this);

  dBusConnection.connect(MCE_SERVICE, MCE_SIGNAL_PATH, MCE_SIGNAL_IF,
                         MCE_DISPLAY_SIG, this, SLOT(displayStateChanged(const QDBusMessage &)));

  dBusInterface->callWithCallback(MCE_DISPLAY_STATUS_GET, QList<QVariant>(), this,
                                    SLOT(setDisplayState(QString)),
                                    SLOT(displayStateError(QDBusError)));
#endif

  /**
    Initial values
  */
  setFocusPolicy(Qt::StrongFocus);
  changeNumberOfLines(8);
  changeFontSize(30);
  isStartStopModeActive = false;
  useDeltaTime = false;
  timeOutput = false;
  isScreenSaverDisabled = false;
  actionEnable_full_date->setEnabled(false);
  resetProgram();
#ifdef Q_WS_MAEMO_5
  path = "/home/user/MyDocs/.push-it.rc";
#else
  path = QDir::homePath() + "/.push-it.rc";
#endif
  loadFile();
  resetUi();
}

/**
  Destructor
*/
MainWindow::~MainWindow()
{
  saveFile();
}

/*******************************************************************************
  Private functions
  *****************************************************************************/

QString MainWindow::generateHistoryString()
{
  QString result;
  char tmp[BUFSIZ];
  std::string previousStr, lastStr, firstStr;
  double lastToPrev = 0;
  double lastToStart = 0;

  //do all time queries at the beginning - to keep the delta of the whole
  //application low
  lastStr = overallTime.getLastTimeString();
  previousStr = overallTime.getPreviousTimeString();
  firstStr = overallTime.getStartTimeString();
  lastToPrev = overallTime.getDeltaLastToPrev();
  lastToStart =  overallTime.getDeltaLastToStart();

   snprintf(tmp,BUFSIZ-1,
      "\n"
//      "Δ Delta %.3lfs "
//      "⅀∑ Total %.3lfs "
      "Δ %.3lfs "
      "∑ %.3lfs "
      "Avg %.3lfs"
      ,
      lastToPrev,
      lastToStart,
      lastToStart/(hitCount-1)
      );

  result = tr(tmp);

  if(true == timeOutput)
  {
    result.prepend(lastStr.c_str());
  }

  return result;
}

int MainWindow::resetCounters()
{
  hitCount=-1;
  updateTime();
  overallTime.stop();
  return EXIT_SUCCESS;
}

/**
Function to reset ui specific stuff
*/
int MainWindow::resetUi()
{
  this->mainButton->setText(tr(mainButtonStartText));
  this->actionPause->setText(tr("&Pause"));

  completeString = this->mainButton->text();

  return EXIT_SUCCESS;
}

int MainWindow::toggleTimer()
{
  if(NULL != timer)
  {
    if(timer->isActive())
    {
      timer->stop();;
    }
    else
    {
      timer->start(timerRefreshTimeMs);
    }
    return EXIT_SUCCESS;
  }
  return EXIT_FAILURE;
}

int MainWindow::updateTime()
{
  hitCount++;
  if(1 == hitCount)
  {
    overallTime.start();
  }
  overallTime.update();

  return EXIT_SUCCESS;
}

int MainWindow::toggleActionPause()
{
  QString str = this->actionPause->text();
  if(str == "&Pause" && overallTime.isPaused())
  {
    this->actionPause->setText(tr("R&esume"));
  }
  else
  {
    this->actionPause->setText(tr("&Pause"));
  }
  return EXIT_SUCCESS;
}

QString MainWindow::getHeaderLine()
{
  QString headerLine;
  std::stringstream sstr;

  double time = 0;
  int hours = 0;
  int min = 0;
  double runTime = 0;

  //get the time
  if(useDeltaTime)
  {
    runTime = overallTime.getDeltaNowToLast();
  }
  else
  {
    runTime = overallTime.getDeltaNowToStart();
  }

  sstr << "#" << hitCount << " ";
  sstr << std::setfill('0');
  hours = (int)(runTime/3600);
  sstr << hours << ":"; //hour
  time = runTime - 3600*hours;
  min = (int)(time/60);
  sstr << std::setw(2) << min << ":"; //minute
  time = runTime - 3600*hours - 60*min;
  sstr.setf(std::ios::fixed);
  sstr.setf(std::ios::showpoint);
  sstr.precision(1);
  sstr << std::setw(4) << time << " "; //seconds
  if(true == timeOutput)
  {
    sstr << "#0 " << overallTime.getStartTimeString();
  }

  headerLine = sstr.str().c_str();
  return headerLine;
}

/*******************************************************************************
  Functions for the basic ui setup
  *****************************************************************************/

void MainWindow::setupUi()
{
  if (this->objectName().isEmpty())
  {
    this->setObjectName(QString::fromUtf8("MainWindow"));
  }
  setBaseSize(800,480);
  resize(800,480);

  /* main button */
  mainButton = new QPushButton;
  mainButton->setObjectName(QString::fromUtf8("mainButton"));
  QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
  mainButton->setSizePolicy(sizePolicy);

  QFont font1;
  font1.setPointSize(26);
  font1.setBold(true);
  font1.setWeight(75);

  mainButton->setFont(font1);
  mainButton->setAutoFillBackground(true);
  mainButton->setDefault(true);
  mainButton->setFlat(true);
  mainButton->setStyleSheet("text-align:center;");;

  /* default font */
  QFont font;
  font.setPointSize(12);
  this->setFont(font);

  /* central widget */
  centralWidget = new QWidget(this);
  centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
  this->setCentralWidget(centralWidget);

  QHBoxLayout *mainLayout = new QHBoxLayout;
  mainLayout->addWidget(mainButton);
  centralWidget->setLayout(mainLayout);

  /* actions for te menu */
  actionReset = new QAction(this);
  actionReset->setObjectName(QString::fromUtf8("actionReset"));

  actionPause = new QAction(this);
  actionPause->setObjectName(QString::fromUtf8("actionPause"));

  actionStartStopMode = new QAction(this);
  actionStartStopMode->setObjectName(QString::fromUtf8("actionStartStopMode"));
  actionStartStopMode->setCheckable(true);

  actionShow_full_list = new QAction(this);
  actionShow_full_list->setObjectName(QString::fromUtf8("actionShow_full_list"));

  actionAbout = new QAction(this);
  actionAbout->setObjectName(QString::fromUtf8("actionAbout"));

  actionEnable_full_date = new QAction(this);
  actionEnable_full_date->setObjectName(QString::fromUtf8("actionEnable_full_date"));
  actionEnable_full_date->setCheckable(true);

  actionEnable_time_and_date = new QAction(this);
  actionEnable_time_and_date->setObjectName(QString::fromUtf8("actionEnable_time_and_date"));
  actionEnable_time_and_date->setCheckable(true);

  action_Fullscreen = new QAction(this);
  action_Fullscreen->setObjectName(QString::fromUtf8("action_Fullscreen"));
  action_Fullscreen->setCheckable(true);

  actionResetFs = new QAction(this);
  actionResetFs->setObjectName(QString::fromUtf8("actionResetFs"));

  actionChangeNumberOfLines = new QAction(this);
  actionChangeNumberOfLines->setObjectName(QString::fromUtf8("actionChangeNumberOfLines"));

  actionChangeFontSize = new QAction(this);
  actionChangeFontSize->setObjectName(QString::fromUtf8("actionChangeFontSize"));

  actionUseDeltaTime= new QAction(this);
  actionUseDeltaTime->setObjectName(QString::fromUtf8("actionUseDeltaTime"));
  actionUseDeltaTime->setCheckable(true);

#ifdef Q_WS_MAEMO_5
  actionDisableScreensaver = new QAction(this);
  actionDisableScreensaver->setObjectName(QString::fromUtf8("actionDisableScreensaver"));
  actionDisableScreensaver->setCheckable(true);
#endif

  /* menu */
  menuBar = new QMenuBar(this);
  menuBar->setObjectName(QString::fromUtf8("menuBar"));
  menuBar->setGeometry(QRect(0, 0, 800, 25));
  menuPush_It_Menu = new QMenu(menuBar);
  menuPush_It_Menu->setObjectName(QString::fromUtf8("menuPush_It_Menu"));
  menuHelp = new QMenu(menuBar);
  menuHelp->setObjectName(QString::fromUtf8("menuHelp"));
  menuData = new QMenu(menuBar);
  menuData->setObjectName(QString::fromUtf8("menuData"));
  menuView = new QMenu(menuBar);
  menuView->setObjectName(QString::fromUtf8("menuView"));
  this->setMenuBar(menuBar);

  menuBar->addAction(menuPush_It_Menu->menuAction());
  menuBar->addAction(menuView->menuAction());
  menuBar->addAction(menuData->menuAction());
  menuBar->addAction(menuHelp->menuAction());
  menuPush_It_Menu->addAction(actionReset);
  menuPush_It_Menu->addAction(actionPause);
  menuPush_It_Menu->addAction(actionStartStopMode);
  menuHelp->addAction(actionAbout);
  menuData->addAction(actionEnable_time_and_date);
  menuData->addAction(actionEnable_full_date);
  menuData->addSeparator();
  menuData->addAction(actionShow_full_list);
  menuView->addAction(action_Fullscreen);
  menuView->addAction(actionResetFs);
  menuView->addAction(actionChangeNumberOfLines);
  menuView->addAction(actionChangeFontSize);
  menuView->addAction(actionUseDeltaTime);
#ifdef Q_WS_MAEMO_5
  menuView->addAction(actionDisableScreensaver);
#endif

  retranslateUi();

  QMetaObject::connectSlotsByName(this);
} // setupUi

void MainWindow::retranslateUi()
{
  this->setWindowTitle(QApplication::translate("MainWindow", releaseInfo.getPackageName().c_str(), 0, QApplication::UnicodeUTF8));
  actionReset->setText(QApplication::translate("MainWindow", "&Reset", 0, QApplication::UnicodeUTF8));
  actionPause->setText(QApplication::translate("MainWindow", "&Pause", 0, QApplication::UnicodeUTF8));
  actionStartStopMode->setText(QApplication::translate("MainWindow", "&Start+Pause Mode", 0, QApplication::UnicodeUTF8));

  actionShow_full_list->setText(QApplication::translate("MainWindow", "Show+save full &list", 0, QApplication::UnicodeUTF8));
  actionEnable_full_date->setText(QApplication::translate("MainWindow", "Enable &full date", 0, QApplication::UnicodeUTF8));
  actionEnable_time_and_date->setText(QApplication::translate("MainWindow", "Enable &time and date", 0, QApplication::UnicodeUTF8));

  action_Fullscreen->setText(QApplication::translate("MainWindow", "&Fullscreen", 0, QApplication::UnicodeUTF8));
  actionResetFs->setText(QApplication::translate("MainWindow", "&Reset+Fullscreen", 0, QApplication::UnicodeUTF8));
  actionChangeNumberOfLines->setText(QApplication::translate("MainWindow", "&Lines", 0, QApplication::UnicodeUTF8));
  actionChangeFontSize->setText(QApplication::translate("MainWindow", "Font &size", 0, QApplication::UnicodeUTF8));
  actionUseDeltaTime->setText(QApplication::translate("MainWindow", "Show delta &time", 0, QApplication::UnicodeUTF8));
  actionAbout->setText(QApplication::translate("MainWindow", "&About", 0, QApplication::UnicodeUTF8));
#ifdef Q_WS_MAEMO_5
  actionDisableScreensaver->setText(QApplication::translate("MainWindow", "&Disable Screensaver", 0, QApplication::UnicodeUTF8));
#endif

  mainButton->setText(QApplication::translate("MainWindow", "Start", 0, QApplication::UnicodeUTF8));

  menuPush_It_Menu->setTitle(QApplication::translate("MainWindow", "&Counter", 0, QApplication::UnicodeUTF8));
  menuHelp->setTitle(QApplication::translate("MainWindow", "&Help", 0, QApplication::UnicodeUTF8));
  menuData->setTitle(QApplication::translate("MainWindow", "&Data", 0, QApplication::UnicodeUTF8));
  menuView->setTitle(QApplication::translate("MainWindow", "&View", 0, QApplication::UnicodeUTF8));
} // retranslateUi


/*******************************************************************************
  Functions related to loading and saving the config file
  *****************************************************************************/

int MainWindow::saveFile()
{
  std::ofstream file;
  file.open(path.toStdString().c_str());
  if(!file.is_open())
  {
#ifdef DEBUG_OUTPUT
    std::cout << "No File" << path.toStdString() << std::endl;
#endif
    return EXIT_FAILURE;
  }

  sfm = getSfm();
  if(NULL == sfm)
  {
    return EXIT_FAILURE;
  }

  for(int i = 0; sfm[i].getFunction != NULL; i++)
  {
    file << sfm[i].string.toStdString() << " " << ((this->*(sfm[i].getFunction))()) << std::endl;
  }
  file.close();
  return EXIT_SUCCESS;
}

int MainWindow::loadFile()
{
  std::ifstream file;
  file.open(path.toStdString().c_str());
  if(!file.is_open())
  {
#ifdef DEBUG_OUTPUT
    std::cout << "No File" << path.toStdString() << std::endl;
#endif
    return EXIT_FAILURE;
  }

  StringFunctionMap *sfm = getSfm();
  if(NULL == sfm)
  {
    return EXIT_FAILURE;
  }

  try
  {
    std::string tmp;
    while(std::getline(file,tmp))
    {
      for(int i = 0; sfm[i].getFunction != NULL; i++)
      {
        size_t found = tmp.find(sfm[i].string.toStdString());
        if(found != std::string::npos)
        {
          QString tmp2 = tmp.c_str();
          QStringList helper = tmp2.split(" ");
          if(helper.length() > 1)
          {
            bool ok;
            int x = helper[1].toInt(&ok,10);
            if(true == ok)
            {
#ifdef DEBUG_OUTPUT
              std::cout << helper[0].toStdString() << " " << x << " " << (this->*(sfm[i].setFunction))(x) << std::endl;
#else
              (this->*(sfm[i].setFunction))(x);
#endif
              break;
            }
          }
          break;
        }
      }
    }
  }
  catch(std::ifstream::failure e)
  {
    if(!file.eof())
      std::cerr << e.what() <<'\n';
  }

  return EXIT_SUCCESS;
}

/*
Functions to get ui specific behavior flags
*/

int MainWindow::getNumberOfLines()
{
  return maximumNumberOfLines;
}
int MainWindow::getFontSize()
{
  return fontSize;
}
int MainWindow::getDeltaModeFlag()
{
  return useDeltaTime;
}
int MainWindow::getStartPauseFlag()
{
  return isStartStopModeActive;
}
int MainWindow::getShowTimeDateFlag()
{
  return timeOutput;
}
int MainWindow::getShowFullDateFlag()
{
  return overallTime.isDateForStringsEnabled();
}
int MainWindow::getScreensaverDisabledFlag()
{
  return isScreenSaverDisabled;
}
int MainWindow::getFullscreenFlag()
{
  return (windowState() & Qt::WindowFullScreen);
}

/*
Functions to set ui specific behavior flags
*/

int MainWindow::setNumberOfLines(int n)
{
  changeNumberOfLines(n);
  return (maximumNumberOfLines);
}
int MainWindow::setFontSize(int n)
{
  changeFontSize(n);
  return (fontSize);
}
int MainWindow::setDeltaModeFlag(int n)
{
  actionUseDeltaTime->setChecked(bool(n));
  return (useDeltaTime = bool(n));
}
int MainWindow::setStartPauseFlag(int n)
{
  actionStartStopMode->setChecked(bool(n));
  return (isStartStopModeActive = bool(n));
}
int MainWindow::setShowTimeDateFlag(int n)
{
  actionEnable_time_and_date->setChecked(bool(n));
  actionEnable_full_date->setEnabled(bool(n));
  return (timeOutput = bool(n));
}
int MainWindow::setShowFullDateFlag(int n)
{
  overallTime.setDateForStrings(bool(n));
  actionEnable_full_date->setChecked(bool(n));
  return bool(n);
}
int MainWindow::setScreensaverDisabled(int n)
{
#ifdef Q_WS_MAEMO_5
  isScreenSaverDisabled = !bool(n); //inverted logic for toggle function
  actionDisableScreensaver->setChecked(bool(n));
  toggleDisableScreensaver();
  return isScreenSaverDisabled;
#endif
  return n;
}
int MainWindow::setFullscreen(int n)
{
  if(n > 0)
  {
    fsExitButton->show();
    showFullScreen();
    action_Fullscreen->setChecked(true);
  }
  else
  {
    action_Fullscreen->setChecked(false);
    showNormal();
  }
  return getFullscreenFlag();
}


MainWindow::StringFunctionMap* MainWindow::getSfm()
{
  static StringFunctionMap sfmx[]=
  {
    {"lines",
     &MainWindow::getNumberOfLines,
     &MainWindow::setNumberOfLines},
{"size",
 &MainWindow::getFontSize,
 &MainWindow::setFontSize},
{"deltaMode",
 &MainWindow::getDeltaModeFlag,
 &MainWindow::setDeltaModeFlag},
{"showTimeDate",
 &MainWindow::getShowTimeDateFlag,
 &MainWindow::setShowTimeDateFlag},
{"showFullDate",
 &MainWindow::getShowFullDateFlag,
 &MainWindow::setShowFullDateFlag},
{"startPauseMode",
 &MainWindow::getStartPauseFlag,
 &MainWindow::setStartPauseFlag},
{"disableScreensaver",
 &MainWindow::getScreensaverDisabledFlag,
 &MainWindow::setScreensaverDisabled},
{"fullscreen",
 &MainWindow::getFullscreenFlag,
 &MainWindow::setFullscreen},
 {"",
 NULL,
 NULL}
  };

  return sfmx;
}

/*******************************************************************************
  Functions which are directly related to the main button
  *****************************************************************************/
/**
Function to handle the different modes of the main button
*/
void MainWindow::mainButtonHandler()
{
  if(true == isStartStopModeActive)
  {
    if(!timer->isActive())
    {
      if(hitCount > 1)
      {
        pauseCounting();
      }
      else
      {
        mainButtonRefresh();
      }
    }
    else
    {
      mainButtonRefresh();
      pauseCounting();
    }
  }
  else
  {
    mainButtonRefresh();
  }

  return;
}

void MainWindow::mainButtonRefresh()
{
  updateTime();
  QString latest = generateHistoryString();
  QString header = getHeaderLine();
  QString string = completeString.remove(mainButtonStartText);
  QStringList lines;

  /* timer handling */
  if(NULL != timer)
  {
    if(1 == hitCount)
    {
      timer->start(timerRefreshTimeMs);
    }
    else if(hitCount > 1)
    {
      if(!timer->isActive())
      {
        timer->start(timerRefreshTimeMs);
      }
    }
  }

  mainButtonRefreshTextOnly();
  if(1 == hitCount)
  {
    return;
  }
  lines = string.split("\n");

  /* add new entry information directly behind the current header
       wihtout start information if there is any.
    */
  if(lines.length() > 0)
  {
    if(lines[0].indexOf("#0") > 0)
    {
      lines[0].truncate(lines[0].indexOf("#0"));
    }
    lines[0].append(latest);
  }

  string = lines.join("\n").prepend("\n").prepend(header);
  completeString = string;
  lines = string.split("\n");
  /* adjust the total number of lines of the button */
  if(lines.length() > maximumNumberOfLines)
  {
    while(lines.length() > maximumNumberOfLines
          && lines.length() > 0)
    {
      lines.removeLast();
    }
  }
  else if(lines.length() < maximumNumberOfLines)
  {
    while(lines.length() < maximumNumberOfLines)
    {
      lines.append(" ");
    }
  }
  string = lines.join("\n");
  this->mainButton->setText(tr(string.toStdString().c_str()));
  toggleActionPause();
#ifdef DEBUG_OUTPUT
  std::cout << "---" << std::endl << string.toStdString() << std::endl << "-" << string.split("\n").length() << "-" << std::endl;
#endif
}

/*
Function to use when the text itself is not changed but the number of lines or
the formatting of the text
*/
void MainWindow::mainButtonRefreshTextOnly()
{
  QString string = completeString;
  QStringList lines;
  QString header = getHeaderLine();

  if(0 == hitCount)
  {
    return; //nothing to do
  }
  else if(1 == hitCount)
  {
    string = header;
  }

  lines = string.split("\n");
  //only change the first line if it is not the inital string
  if(string.indexOf("Start") < 0)
  {
    if(lines.length() > 0)
    {
      lines[0] = header;
    }
  }

  /* adjust the total number of lines of the button */
  if(lines.length() > maximumNumberOfLines)
  {
    while(lines.length() > maximumNumberOfLines
          && lines.length() > 0)
    {
      lines.removeLast();
    }
  }
  else if(lines.length() < maximumNumberOfLines)
  {
    while(lines.length() < maximumNumberOfLines)
    {
      lines.append(" ");
    }
  }

  string = lines.join("\n");
  this->mainButton->setText(tr(string.toStdString().c_str()));
}

void MainWindow::mainButtonTimeoutUpdate()
{
  if(NULL != timer)
  {
    if(!timer->isActive())
    {
      assert(0 && "Unintended use");
      return;
    }
    else if(overallTime.isPaused())
    {
      timer->stop();
      return;
    }
  }

  QString string = this->mainButton->text();
  QStringList lines = string.split("\n");
  QString header = getHeaderLine();

  if(lines.length() >= 1)
  {
    lines[0] = header;
  }
  else
  {
    assert(0 && "Lines are missing");
  }
  //update device
  //update ui
  this->mainButton->setText(tr(lines.join("\n").toStdString().c_str()));

  //update stored string
  lines = completeString.split("\n");
  if(lines.length() >= 1)
  {
    lines[0] = header;
  }
  completeString = lines.join("\n");
}

/*******************************************************************************
Slot functions (signal receivers)
*******************************************************************************/
void MainWindow::pauseCounting()
{
  toggleTimer();
  overallTime.pause();
  toggleActionPause();
}

void MainWindow::changeNumberOfLines(int number)
{
  int maxLines = 1000;
  bool ok = true;
  if(number == 0)
  {
    number = QInputDialog::getInt(this, tr("Lines"),
                                  tr("Number of lines to be displayed:"),
                                  maximumNumberOfLines, 0, maxLines, 1,
                                  &ok);
  }

  if(false == ok)
  {
    return;
  }
  else if (number > 0 && number < maxLines)
  {
    maximumNumberOfLines = number;
  }
  else
  {
    QString text;
    text.sprintf("Invalid entry. Try something like \"4\" (max %i).",maxLines);
    QMessageBox::information(this, tr("Invalid entry"),
                             tr(text.toStdString().c_str()));
    return;
  }

  QString actionText = actionChangeNumberOfLines->text();
  actionText = "&Lines (";
  actionText += QString::number(maximumNumberOfLines);
  actionText += ")";
  actionChangeNumberOfLines->setText(actionText);
  mainButtonRefreshTextOnly();
}

void MainWindow::changeFontSize(int size)
{
  int maxSize = 100;
  bool ok = false;
  QFont font = mainButton->font();
  if(size == 0)
  {
    size = QInputDialog::getInt(this, tr("Font size"),
                                  tr("Font size:"),
                                  font.pointSize(), 0, maxSize, 1,
                                  &ok);
  }
  else
  {
    ok = true;
  }

  if(false == ok)
  {
    return;
  }
  else if (size > 0 && size < maxSize)
  {
    font.setPointSize(size);
    mainButton->setFont(font);
  }
  else
  {
    QString text;
    text.sprintf("Invalid entry. Try something like \"28\" (max %i).",maxSize);
    QMessageBox::information(this, tr("Invalid entry"),
                             tr(text.toStdString().c_str()));
    return;
  }

  fontSize = size;
  QString actionText = actionChangeFontSize->text();
  actionText = "Font &size (";
  actionText += QString::number(size);
  actionText += ")";
  actionChangeFontSize->setText(actionText);
  mainButtonRefreshTextOnly();
}

/**
  Toggle Functions
*/

void MainWindow::toggleStartStopMode()
{
  if(true == isStartStopModeActive)
  {
    isStartStopModeActive = false;
  }
  else
  {
    isStartStopModeActive = true;
  }
  return;
}

void MainWindow::toggleUseDeltaTime()
{
  if(true == useDeltaTime)
  {
    useDeltaTime = false;
  }
  else
  {
    useDeltaTime = true;
  }
}

void MainWindow::toggleFullDate()
{
  if(overallTime.isDateForStringsEnabled())
  {
    overallTime.setDateForStrings(false);
  }
  else
  {
    overallTime.setDateForStrings(true);
  }
}

void MainWindow::toggleTimeDate()
{
  if(this->actionEnable_time_and_date->isChecked())
  {
    this->actionEnable_full_date->setEnabled(true);
    timeOutput = true;
  }
  else
  {
    this->actionEnable_full_date->setDisabled(true);
    timeOutput = false;
  }
}

#ifdef Q_WS_MAEMO_5
void MainWindow::toggleDisableScreensaver()
{
#ifdef QT_SCREENSAVER_HANDLING
  static QtMobility::QSystemScreenSaver *saver = NULL;
#endif

  if(false == isScreenSaverDisabled)
  {
#ifdef MCE_SCREENSAVER_HANDLING
    QDBusConnection::systemBus().call(QDBusMessage::createMethodCall(MCE_SERVICE, MCE_REQUEST_PATH,
                                                                     MCE_REQUEST_IF, MCE_PREVENT_BLANK_REQ));
#endif
#ifdef QT_SCREENSAVER_HANDLING
    if(NULL == saver)
    {
      saver = new QtMobility::QSystemScreenSaver();
      saver->setScreenSaverInhibit();
    }
#endif
    isScreenSaverDisabled = true;
  }
  else
  {
#ifdef MCE_SCREENSAVER_HANDLING
    //no idea yet
#endif
#ifdef QT_SCREENSAVER_HANDLING
    if(NULL != saver)
    {
      saver->deleteLater();
      saver = NULL;
    }
#endif
    isScreenSaverDisabled = false;
  }
}
#endif

/**
Function to reset the program to a initial state
*/
void MainWindow::resetProgram()
{
  resetCounters();
  resetUi();
  if(NULL != timer)
  {
    if(timer->isActive())
    {
      timer->stop();
    }
  }
}

void MainWindow::resetProgramAndFullscreen()
{
  resetProgram();
  setFullscreen(1);
}

/**
Function to save generated values to a file directly without viewing
Currently unused.
*/
void MainWindow::saveToFile()
{
  ShowFullListDialog *listHandler;
  listHandler = new ShowFullListDialog(0,completeString);
  listHandler->save();
}

void MainWindow::about()
{
  static AboutDialog *pa = NULL;

  if(NULL == pa)
  {
    pa = new AboutDialog;
    QTextBrowser *examples = new QTextBrowser;
    examples->setOpenExternalLinks(true);
    examples->setHtml(
        "<p><b><a href =\"http://sites.google.com/site/markusscharnowski/n/pushit/real-life-examples\">Examples website with videos and pictures.</a></b></p>"
        "<p>"
        "<b>Warning to be read, if the examples are followed:</b><br>"
        "If this program is used uncautiously you could break your device physically. Always be sure that you use this software and the corresponding hardware in a way that the hardware won't get damaged."
        "</p>"
        "<p><b>Excerpt:</b></p>"
        "<p><b>Pull ups</b></p>"
        "<p>Place the phone add the position where you are in the highest position, so you can hit it with your nose. In my case I mount the Nokia N900 above a door with the help of some tesa-strips. I also tried it without tesa-strips but after some pushes on the N900 I was too anxious that it could fall down on the floor. So I recommend some safety mechanism to have fun with your device now and in the future. Every time you pulling yourself up, you touch the screen of the N900 with your nose. So you will always know how many pull ups you have done.</p>"

        "<p><b>Push ups</b></p>"
        "<p>Place the smartphone just below your nose so you can hit it with the nose when in the lowest position. And then start pushing up.</p>"

        "<p><b>Crunches</b></p>"
        "Doing crunches is a tiny bit more tricky. You have to go into your crunching position (laying on your back, feet up) and place your phone behind your head. Positioned well, you will be able to touch your phone with one of your thumbs every time you are going down (assuming you fold your hands behind your head when doing crunches)."

        "<p><b>Lower back exercise</b></p>"
        "<p>Place the phone just below your nose so you can hit it with the nose. I don't know how this exercise is called - if you know it, please let me know it too.<br>"
        "To execute this exercise I lay myself on some pillows on a bench. My legs will get support by a table. The exercise itself is moving you upper body down to the phone and up again till your back is strait like when your are standing on your feet.</p>"
        );

    QString name = releaseInfo.getPackageNameQ() + " " + releaseInfo.getPackageVersionQ();
    pa->setProgramName(name);
    pa->setProgramDate(releaseInfo.getPackageDateQ());
    pa->setProgramUrl("http://sites.google.com/site/markusscharnowski/n/pushit");
    pa->tabs->insertTab(5,examples,tr("&Examples"));
    pa->setMinimumHeight(400);
    pa->setFeedbackHtmlText(
        "<p>Do you have ideas for improving the program? You want a specific functionality? "
        "You have found a bug?</p>"
        "<p><a href=\"http://code.google.com/p/push-it/issues/list\">Bugtracker</a></p>"
        "<p>Email <a href=\"mailto:markus.scharnowski@gmail.com?subject=SW Feedback " + windowTitle() +
        " &body=Hello Markus,\">Feedback</a></p>"
        );
  }
  pa->show();
}

void MainWindow::showFullList()
{
  ShowFullListDialog *ps = new ShowFullListDialog(0,completeString);
  ps->show();
}

void MainWindow::showFullScreenHandler()
{
  setFullscreen(!getFullscreenFlag());
}

void MainWindow::slotFullscreenExit()
{
  action_Fullscreen->trigger();
}


#ifdef DO_SCREEN_HANDLING
/*******************************************************************************
  Handling the screen state (turning on/off counting/screen refresh)
  *****************************************************************************/
void MainWindow::displayStateChanged(const QDBusMessage &message)
{
    QString state = message.arguments().at(0).toString();
    setDisplayState(state);
}

void MainWindow::displayStateError(const QDBusError &error)
{

}

void MainWindow::setDisplayState(const QString &state)
{
  if (!state.isEmpty())
  {
    if (state == MCE_DISPLAY_ON_STRING) //display on
    {
      if(timer && !timer->isActive() && overallTime.isActive())
      {
        timer->start();
      }
    }
    else if (state == MCE_DISPLAY_OFF_STRING) //Display off
    {
      if(timer && timer->isActive() && overallTime.isActive())
      {
        timer->stop();
      }
    }
  }
}
#endif

/*******************************************************************************
  Modified Events

  Unfortuneately the events show/hide are never called in maemo. So they only
  make sense for the desktop version.
  *****************************************************************************/
void MainWindow::showEvent(QShowEvent *e)
{
#ifdef DEBUG_EVENT_OUTPUT
  std::cout << __func__ << std::endl;
#endif
  if(timer && !timer->isActive() && overallTime.isActive())
  {
    timer->start();
  }
  QWidget::showEvent(e);
}

void MainWindow::hideEvent(QHideEvent *e)
{
#ifdef DEBUG_EVENT_OUTPUT
  std::cout << __func__ << std::endl;
#endif
  if(timer && timer->isActive() && overallTime.isActive())
  {
    timer->stop();
  }
  QWidget::hideEvent(e);
}
